import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'Address.dart';
import 'dio_log_intercepor.dart';
import 'http_entity.dart';

///网络请求成功,并且服务端code 返回值成功 object
typedef Success = Function<T>(T t);

///网络请求成功,并且服务端code 返回值成功 list
typedef ListSuccess = Function<T>(List<T> list);

///网络请求成功,服务端code 返回值失败
typedef Fail = Function(FailEntity failEntity);

///网络请求失败，无法连接服务器或者服务端返回的状态码不是200，可以统一处理
typedef Error = Function(ErrorEntity);

///网络请求完成
typedef Complete = Function();

///服务端code,message返回回调
typedef FlagCallBack = Function(FlagEntity);

class Http {
  static Http get instance => _getInstance();

  static Http _instance;

  Dio _dio;

  Http._internal() {
    if (_dio == null) {
      _dio = _initDio();
    }
  }

  // 静态、同步、私有访问点
  static Http _getInstance() {
    if (_instance == null) {
      _instance = new Http._internal();
    }
    return _instance;
  }

  int _timeout = 20000;

  Dio _initDio() {
    Dio dio = Dio(BaseOptions(
      connectTimeout: _timeout,
      receiveTimeout: _timeout,
      sendTimeout: _timeout,
      baseUrl: Address.debugBaseUrl,
      responseType: ResponseType.plain,
    ));
    dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
      dio.lock();
      options.headers.addAll({
        "Platform-Type":"platC",
        "Language":'en',
        // 'Authorization':SharedPreferencesUtils.getData(SharedPreferencesUtils.tokenKey)??''
      });
      dio.unlock();
      return options;
    },onResponse: (response){
      dio.lock();
      if(jsonDecode(response.data)["code"] == 401){
        // BotToast.showText(text: "身份信息过期，请重新登陆");
        // NavigationService.getInstance().navigateTo('/LoginPage');
      }
      dio.unlock();
      return response;
    }));

    dio.interceptors
      ..add(PrettyDioLogger(
        requestBody: true,
        requestHeader: true,
      ));
    return dio;
  }

  /// get请求返回数据类型是object
  Future get<T>(String url, Map<String, dynamic> queryParameters,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false}) {
    return _request<T>(
      'get',
      url,
      queryParameters,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      isBanquet: isBanquet,
    );
  }

  /// post请求返回数据类型是object
  Future post<T>(String url, data,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        ProgressCallback progressCallback,
        bool isBanquet = false}) {
    return _request<T>(
      'post',
      url,
      data,
      onSuccess: onSuccess,
      onFlagCallBack: onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      progressCallback: progressCallback,
      isBanquet: isBanquet,
    );
  }

  /// put请求返回数据类型是object
  Future put<T>(String url, data,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        ProgressCallback progressCallback,
        bool isBanquet = false}) {
    return _request<T>(
      'put',
      url,
      data,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      progressCallback: progressCallback,
      isBanquet: isBanquet,
    );
  }

  /// query请求返回数据类型是object
  Future query<T>(String url, data,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        ProgressCallback progressCallback,
        bool isBanquet = false}) {
    return _request<T>(
      'query',
      url,
      data,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      progressCallback: progressCallback,
      isBanquet: isBanquet,
    );
  }

  /// post请求返回数据类型是object
  Future delete<T>(String url, data,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        ProgressCallback progressCallback,
        bool isBanquet = false}) {
    return _request<T>(
      'delete',
      url,
      data,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      progressCallback: progressCallback,
      isBanquet: isBanquet,
    );
  }

  /// patch请求返回数据类型是object
  Future patch<T>(String url, data,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        ProgressCallback progressCallback,
        bool isBanquet = false}) {
    return _request<T>(
      'patch',
      url,
      data,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      progressCallback: progressCallback,
      isBanquet: isBanquet,
    );
  }

  /// get请求返回数据类型是list
  Future getList<T>(String url, Map<String, dynamic> queryParameters,
      {Function(List<T>) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false}) {
    return _requestList<T>(
      'get',
      url,
      queryParameters,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      isBanquet: isBanquet,
    );
  }

  /// post请求返回数据类型是list
  void postList<T>(
      String url,
      Map<String, dynamic> data, {
        Function(List<T>) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false,
      }) {
    _requestList<T>(
      'post',
      url,
      data,
      onSuccess: onSuccess,
      onFlagCallBack : onFlagCallBack,
      onFail: onFail,
      onError: onError,
      complete: complete,
      isBanquet: isBanquet,
    );
  }

  /// 请求返回数据类型是object
  Future _request<T>(String method, String url, queryParameters,
      {Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        ProgressCallback progressCallback,
        bool isBanquet = false}) async {
    try {
      _dio.options.baseUrl =
      (kDebugMode ? Address.debugBaseUrl : Address.releaseBaseUrl);
      Response response = await _dio.request(url,
          queryParameters: method == 'get' ? queryParameters : null,
          data: method != 'get' ? queryParameters : null,
          options: Options(method: method),
          onSendProgress: progressCallback);
      if (response != null) {
        BaseEntity entity = BaseEntity<T>.fromJson(
            jsonDecode(_regExpData(response.data.toString())),
            isBanquet: isBanquet);
        if(onFlagCallBack !=null){
          onFlagCallBack(FlagEntity(code: entity.code, message: entity.message));
        }
        if (entity.code == 0 || entity.code == 200) {
          if (onSuccess != null) {

            onSuccess(entity.data);
          }
        } else {
          if (onFail != null) {
            //FLToast.text(text: entity.message);
            onFail(FailEntity(code: entity.code, message: entity.message));
          }
        }
      } else {
        if (onError != null) {
          onError(ErrorEntity(code: -1, message: '响应体为空'));
        }
      }

      if (complete != null) {
        complete();
      }
    } on DioError catch (e) {
      _httpError(onError, complete, e);
    } catch (e) {
      /// 解析过程中的异常
      print('数据解析异常: ${e.toString()}');
      if (onFail != null) {
        onFail(FailEntity(code: -2, message: '数据解析异常'));
      }

      if (complete != null) {
        complete();
      }
    }
  }

  /// get请求返回数据类型是object
  Future _requestList<T>(String method, String url, queryParameters,
      {Function(List<T>) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false}) async {
    try {
      _dio.options.baseUrl =
      kDebugMode ? Address.debugBaseUrl : Address.releaseBaseUrl;
      Response response = await _dio.request(url,
          queryParameters: method == 'get' ? queryParameters : null,
          data: method == 'post' ? queryParameters : null,
          options: Options(method: method));
      print(response.data);
      if (response != null) {
        BaseListEntity entity = BaseListEntity<T>.fromJson(
            jsonDecode(_regExpData(response.data.toString())),
            isBanquet: isBanquet);
        if(onFlagCallBack !=null){
          onFlagCallBack(FlagEntity(code: entity.code, message: entity.message));
        }
        if ((entity.code == 0 && !isBanquet) ||
            (entity.code == 200 && !isBanquet)) {
          if (onSuccess != null) {
            onSuccess(entity.data);
          }
        } else {
          if (onFail != null) {
            onFail(FailEntity(code: entity.code, message: entity.message));
          }
        }
      } else {
        if (onError != null) {
          onError(ErrorEntity(code: -1, message: '响应体为空'));
        }
      }

      if (complete != null) {
        complete();
      }
    } on DioError catch (e) {
      _httpError(onError, complete, e);
    } catch (e) {
      /// 解析过程中的异常
      print('数据解析异常: ${e.toString()}');
      if (onFail != null) {
        onFail(FailEntity(code: -2, message: '数据解析异常'));
      }

      if (complete != null) {
        complete();
      }
    }
  }

  /// http错误
  void _httpError(onError, onComplete, DioError error) {
    if (onError != null) {
      switch (error.type) {
        case DioErrorType.CANCEL:
          {
            onError(ErrorEntity(code: -1, message: "请求取消"));
          }
          break;
        case DioErrorType.CONNECT_TIMEOUT:
          {
            onError(ErrorEntity(code: -1, message: "连接超时"));
          }
          break;
        case DioErrorType.SEND_TIMEOUT:
          {
            onError(ErrorEntity(code: -1, message: "请求超时"));
          }
          break;
        case DioErrorType.RECEIVE_TIMEOUT:
          {
            onError(ErrorEntity(code: -1, message: "响应超时"));
          }
          break;
        case DioErrorType.DEFAULT:
          {
            onError(ErrorEntity(code: -1, message: "请检查网络连接"));
          }
          break;
        case DioErrorType.RESPONSE:
          {
            try {
              onError(ErrorEntity(
                  code: error.response.statusCode, message: '请检查网络连接'));
            } on Exception catch (_) {
              onError(ErrorEntity(code: -1, message: "未知错误"));
            }
          }
          break;
        default:
          {
            onError(ErrorEntity(code: -1, message: error.message));
          }
      }
    }

    if (onComplete != null) {
      onComplete();
    }
  }

  ///替换一些特殊字符
  String _regExpData(String data) {
    return (data ?? '').replaceAllMapped(RegExp(r'[\t\v]'), (match) => '');
  }

  ///上传图片
  Future postFormData<T>(String url,
      Map<String, dynamic> queryParameters,
      {ProgressCallback progressCallback,
        Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false}) async {
    var formData = FormData.fromMap(queryParameters);
    await Http.instance.post<T>(url, formData,
        progressCallback: progressCallback,
        isBanquet: isBanquet,
        onSuccess: onSuccess,
        onError: onError, onFail: onFail,
        complete: complete
    );
  }

  ///上传图片
  Future uploadImage<T>(String url, String path,
      Map<String, dynamic> queryParameters,
      {ProgressCallback progressCallback,
        Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false}) async {


    if(path.isNotEmpty){
      var file = File(path);
      var bool = await file.exists();

      if (!bool) {
        return Future.value(null);
      }

      String fileName = path.substring(path.lastIndexOf("/") + 1);
      queryParameters.addAll({
        'file': await MultipartFile.fromFile(path, filename: fileName),
      });
    }

    var formData = FormData.fromMap(queryParameters);
    await Http.instance.post<T>(url, formData,
        progressCallback: progressCallback,
        isBanquet: isBanquet,
        onSuccess: onSuccess,
        onError: onError, onFail: onFail,
        complete: complete
    );
  }

  ///上传图片
  Future uploadImages<T>(String url, List<String> paths,
      Map<String, dynamic> queryParameters,
      {ProgressCallback progressCallback,
        Function(T) onSuccess,
        FlagCallBack onFlagCallBack,
        Fail onFail,
        Error onError,
        Complete complete,
        bool isBanquet = false}) async {
    List<MultipartFile> multipartFiles = [];
    for(String path in paths) {
      var file = File(path);
      var bool = await file.exists();
      if (bool) {
        String fileName = path.substring(path.lastIndexOf("/") + 1);
        MultipartFile multipartFile = await MultipartFile.fromFile(
            path, filename: fileName);
        multipartFiles.add(multipartFile);
      }
    }
    var formData = FormData.fromMap(queryParameters);
    formData.files.addAll(multipartFiles.map((e){
      return  MapEntry(
        "files",
        e,
      );
    }).toList());
    await Http.instance.post<T>(url, formData,
        progressCallback: progressCallback,
        isBanquet: isBanquet,
        onSuccess: onSuccess,
        onError: onError, onFail: onFail,
        complete: complete
    );
  }
}

